﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Interop;
using System.Diagnostics;
using Lds.Ward.PhotoDirectory.Logic;
using System.IO;
using System.Threading;
using System.Windows.Threading;
using System.ComponentModel;
using Microsoft.Win32;
using Avalon.Windows.Dialogs;
using System.Windows.Documents.Serialization;

namespace Lds.Ward.PhotoDirectory.WpfApp {
	public enum ExportTarget {
		PhotoDirectory,
		BulletinBoardPhotos,
		WebSite,
	}

	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window {
		public static RoutedUICommand NextStep = new RoutedUICommand();
		public static RoutedUICommand PreviousStep = new RoutedUICommand();
		public static RoutedUICommand SkipToEnd = new RoutedUICommand();
		public static RoutedUICommand UnselectAll = new RoutedUICommand();
		public static RoutedUICommand BrowsePhotoFolders = new RoutedUICommand();
		public static RoutedUICommand ExportPhotos = new RoutedUICommand();

		ClipboardWatcher clipboardWatcher;
		bool watchingClipboard;
		Families families { get { return (Families)Resources["familiesCollection"]; } }
		OpenFileDialog openMlsDataFileDialog = new OpenFileDialog();
		FolderBrowserDialog choosePhotoDirectoryDialog = new FolderBrowserDialog();
		SaveFileDialog saveAsXpsDialog = new SaveFileDialog();

		public MainWindow() {
			InitializeComponent();

			//CommandBindings.Add(new CommandBinding(ApplicationCommands.Save, executeSave));
			CommandBindings.Add(new CommandBinding(NextStep, executeNextStep, canExecuteNextStep));
			CommandBindings.Add(new CommandBinding(PreviousStep, executePreviousStep, canExecutePreviousStep));
			CommandBindings.Add(new CommandBinding(SkipToEnd, executeSkipToEnd, canExecuteSkipToEnd));
			CommandBindings.Add(new CommandBinding(ApplicationCommands.SelectAll, executeSelectAll));
			CommandBindings.Add(new CommandBinding(UnselectAll, executeUnselectAll));
			CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, executePaste));
			CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, executeOpen));
			CommandBindings.Add(new CommandBinding(BrowsePhotoFolders, executeBrowsePhotoFolders));
			CommandBindings.Add(new CommandBinding(ExportPhotos, executeExportPhotos, canExecuteExportPhotos));

			openMlsDataFileDialog.Filter = "Text files (*.txt)|*.txt|All files|*.*";
			openMlsDataFileDialog.FilterIndex = 0;
			openMlsDataFileDialog.Title = "Open MLS Data File";

			saveAsXpsDialog.Filter = "XPS Documents (*.xps)|*.xps|All files|*.*";
			saveAsXpsDialog.FilterIndex = 0;
			saveAsXpsDialog.Title = "Save XPS Document";

			choosePhotoDirectoryDialog.Title = "Select photo directory";

			clipboardWatcher = new ClipboardWatcher(this);
			clipboardWatcher.ClipboardChanged += clipboardChanged;
			Activated += new EventHandler(MainWindow_Activated);
			Closed += new EventHandler(MainWindow_Closed);
		}

		void MainWindow_Closed(object sender, EventArgs e) {
			clipboardWatcher.Dispose();
		}

		void MainWindow_Activated(object sender, EventArgs e) {
			watchingClipboard = false;
			MlsCopyClipboardNotifyIcon.Visibility = Visibility.Hidden;
		}

		void clipboardChanged(object sender, RoutedEventArgs e) {
			if (!watchingClipboard) return;
			if (isValidImportData(Clipboard.GetText())) {
				Process p = findMlsProcess();
				if (p != null)
					WinAPI.SendMessage(p.MainWindowHandle, WinAPI.WindowsMessages.WM_SYSCOMMAND,
						(IntPtr)WinAPI.WM_SYSCOMMAND_WPARAM.SC_MINIMIZE, IntPtr.Zero);
				WindowState = WindowState.Normal;
				importFromString(Clipboard.GetText());
			}
		}

		bool isValidImportData(string familiesText) {
			try {
				IList<Family> families = new List<Family>(FlatFile.ToFamilies(new StringReader(familiesText)));
				return families.Count > 0;
			} catch {
				return false;
			}
		}

		void executePaste(object sender, ExecutedRoutedEventArgs e) {
			// See if clipboard is already filled with appropriate MLS data.
			bool clipboardDataPresent = Clipboard.ContainsText(TextDataFormat.Text);
			// See if data is in expected format.
			bool clipboardDataValid = isValidImportData(Clipboard.GetText());

			if (clipboardDataPresent && clipboardDataValid)
				importFromString(Clipboard.GetText());
			else
				getDataFromMls();
		}

		void executeOpen(object sender, ExecutedRoutedEventArgs e) {
			bool? result = openMlsDataFileDialog.ShowDialog(this);
			if (result.HasValue && result.Value) {
				importedFilename.Text = abbreviatePath(openMlsDataFileDialog.FileName, 40);

				families.Clear();
				beginParseFamiliesContent(new StreamReader(openMlsDataFileDialog.OpenFile()));
			}
		}

		void executeBrowsePhotoFolders(object sender, ExecutedRoutedEventArgs e) {
			bool? result = choosePhotoDirectoryDialog.ShowDialog();
			if (result.HasValue && result.Value) {
				photoDirectoryLabel.Text = choosePhotoDirectoryDialog.SelectedPath;
				beginGenerateThumbnails();
			}
		}

		string abbreviatePath(string path, int maxLength) {
			if (path.Length > maxLength) {
				int lastSlash = path.LastIndexOf(System.IO.Path.DirectorySeparatorChar, path.Length - 2);
				string rootPath = System.IO.Path.GetPathRoot(path);
				if (rootPath.Length == lastSlash)
					return path;
				else
					return System.IO.Path.GetPathRoot(path) + "..." + path.Substring(lastSlash);
			}
			return path;
		}

		void getDataFromMls() {
			// Hook to a clipboard event so we know when copy to clipboard has been done.
			watchingClipboard = true;

			// Get out of the way so the user can switch to MLS.
			WindowState = WindowState.Minimized;
			MlsCopyClipboardNotifyIcon.Visibility = Visibility.Visible;
			MlsCopyClipboardNotifyIcon.BalloonTipText = MlsCopyClipboardNotifyIcon.BalloonTipText.Replace(@"\n", Environment.NewLine);
			MlsCopyClipboardNotifyIcon.ShowBalloonTip(10 * 1000);

			// Activate MLS app if it is already running.
			Process mls = findMlsProcess();
			if (mls != null)
				WinAPI.SendMessage(mls.MainWindowHandle, WinAPI.WindowsMessages.WM_SYSCOMMAND,
					(IntPtr)WinAPI.WM_SYSCOMMAND_WPARAM.SC_MAXIMIZE, IntPtr.Zero);
		}

		Process findMlsProcess() {
			Process[] mls = Process.GetProcessesByName("MLS");
			if (mls.Length == 0) return null;
			return mls[0];
		}

		void importFromString(string familiesText) {
			families.Clear();
			beginParseFamiliesContent(new StringReader(familiesText));

			//PhotosPreview.Clear();
			//foreach (Family f in Families)
			//{
			//    string imageKey = f.Surname + ", " + f.FamilyMembers[0].GivenNames;
			//    PhotosPreview.Items.Add(f.Surname, imageKey);
			//    ListViewItem item = new ListViewItem();
			//    item.ImageKey = f.Surname;
			//    item.Text = f.Surname;
			//    item.SubItems.AddRange(new string[] {
			//        f.FamilyMembers[0].GivenNames,
			//        f.MailingAddress.City,
			//        f.MailingAddress.State,
			//        f.MailingAddress.PostalCode,
			//    });
			//    item.Checked = true;
			//    filterListView.Items.Add(item);
			//}

			//GenerateThumbnailsForPreview(busy);
		}

		Thread importContentThread;
		void beginParseFamiliesContent(TextReader familiesReader) {
			if (importContentThread != null) {
				throw new InvalidOperationException(Strings.ImportInProgress);
			}
			workingLabel.Visibility = Visibility.Visible;
			importContentThread = new Thread((ThreadStart)delegate {
				try {
					foreach (Family f in FlatFile.ToFamilies(familiesReader)) {
						Dispatcher.Invoke(DispatcherPriority.Background, (ThreadStart)delegate {
							families.Add(f);
						});
					}
					Dispatcher.BeginInvoke(DispatcherPriority.Normal,
						(ThreadStart)delegate {
						familyFilterListView.SelectAll();
						workingLabel.Visibility = Visibility.Hidden;
					});
				} finally {
					familiesReader.Close();
					importContentThread = null;
				}
				beginGenerateThumbnails();
			});
			importContentThread.Start();
		}

		Thread generateThumbnailsThread;
		void beginGenerateThumbnails() {
			if (generateThumbnailsThread != null) {
				throw new InvalidOperationException(Strings.ThumbnailGenerationInProgress);
			}
			string photoDirectory = null;
			Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate {
				workingLabel.Visibility = Visibility.Visible;
				photoDirectory = photoDirectoryLabel.Text;
			});
			generateThumbnailsThread = new Thread((ThreadStart)delegate {
				foreach (Family f in families) {
					f.ImagePath = f.GetPhotoPath(new DirectoryInfo(photoDirectory));
				}
				Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate {
					workingLabel.Visibility = Visibility.Hidden;
				});
				generateThumbnailsThread = null;
			});
			generateThumbnailsThread.Start();
		}

		void cancelPasteButton_Click(object sender, RoutedEventArgs e) {
			WindowState = WindowState.Normal;
			Focus();
		}

		void showNotifyPrompt_Click(object sender, RoutedEventArgs e) {
			MlsCopyClipboardNotifyIcon.ShowBalloonTip(10 * 1000);
		}

		void executeSelectAll(object sender, ExecutedRoutedEventArgs e) {
			familyFilterListView.SelectAll();
		}

		void executeUnselectAll(object sender, ExecutedRoutedEventArgs e) {
			familyFilterListView.UnselectAll();
		}

		void executePreviousStep(object sender, ExecutedRoutedEventArgs e) {
			tabs.SelectedIndex--;
		}
		void canExecutePreviousStep(object sender, CanExecuteRoutedEventArgs e) {
			e.CanExecute = tabs.SelectedIndex > 0;
			e.Handled = true;
		}

		void executeNextStep(object sender, ExecutedRoutedEventArgs e) {
			tabs.SelectedIndex++;
		}
		void canExecuteNextStep(object sender, CanExecuteRoutedEventArgs e) {
			e.CanExecute = tabs.SelectedIndex < tabs.Items.Count - 1;
			e.Handled = true;
		}

		void executeSkipToEnd(object sender, ExecutedRoutedEventArgs e) {
			tabs.SelectedIndex = tabs.Items.Count - 1;
		}
		void canExecuteSkipToEnd(object sender, CanExecuteRoutedEventArgs e) {
			e.CanExecute = tabs.SelectedIndex < tabs.Items.Count - 1;
			e.Handled = true;
		}

		void executeExportPhotos(object sender, ExecutedRoutedEventArgs e) {
			bool? result = saveAsXpsDialog.ShowDialog(this);
			if (result.HasValue && result.Value) {
				using (Stream stream = saveAsXpsDialog.OpenFile()) {
					// Create a SerializerProvider for accessing plug-in serializers.
					SerializerProvider serializerProvider = new SerializerProvider();

					// Locate the serializer that matches the fileName extension.
					SerializerDescriptor selectedPlugIn = null;
					foreach (SerializerDescriptor serializerDescriptor in
									serializerProvider.InstalledSerializers) {
						if (serializerDescriptor.IsLoadable &&
							 saveAsXpsDialog.FileName.EndsWith(serializerDescriptor.DefaultFileExtension)) {   // The plug-in serializer and fileName extensions match.
							selectedPlugIn = serializerDescriptor;
							break; // foreach
						}
					}

					// If a match for a plug-in serializer was found,
					// use it to output and store the document.
					if (selectedPlugIn != null) {
						SerializerWriter serializerWriter =
							serializerProvider.CreateSerializerWriter(selectedPlugIn,
																	  stream);
						serializerWriter.Write(flowDocumentPageViewer.Document.DocumentPaginator);
					}
				}
			}
			e.Handled = true;
		}
		void canExecuteExportPhotos(object sender, CanExecuteRoutedEventArgs e) {
			e.CanExecute = families.Count > 0 && photoDirectoryLabel.Text.Length > 0;
			e.Handled = true;
		}
	}
}
